using System;
using System.ComponentModel;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.Design;

namespace Altairis.Web.UI.WebControls {

    public sealed class Role {

        /// <summary>
        /// Gets or sets the name of the role.
        /// </summary>
        /// <value>The name of the role.</value>
        public string RoleName { get; set; }

        /// <summary>
        /// Gets or sets the user count.
        /// </summary>
        /// <value>The user count.</value>
        public int UserCount { get; set; }
    }

    [ToolboxData("<{0}:RolesDataSource runat=server />")]
    [Designer(typeof(RolesDataSourceDesigner))]
    public class RolesDataSource : DataSourceControl {
        private RolesView roles;

        /// <summary>
        /// Gets the named data source view associated with the data source control.
        /// </summary>
        /// <param name="viewName">The name of the <see cref="T:System.Web.UI.DataSourceView"/> to retrieve. In data source controls that support only one view, such as <see cref="T:System.Web.UI.WebControls.SqlDataSource"/>, this parameter is ignored.</param>
        /// <returns>
        /// Returns the named <see cref="T:System.Web.UI.DataSourceView"/> associated with the <see cref="T:System.Web.UI.DataSourceControl"/>.
        /// </returns>
        protected override DataSourceView GetView(string viewName) {
            if (!string.IsNullOrEmpty(viewName) && !viewName.Equals("MembershipRoles", StringComparison.OrdinalIgnoreCase)) throw new ArgumentOutOfRangeException("viewName", viewName, "Specified view does not exists.");
            if (this.roles == null) this.roles = new RolesView(this, viewName);
            return this.roles;
        }

        /// <summary>
        /// Gets a collection of names, representing the list of <see cref="T:System.Web.UI.DataSourceView"/> objects associated with the <see cref="T:System.Web.UI.DataSourceControl"/> control.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.ICollection"/> that contains the names of the <see cref="T:System.Web.UI.DataSourceView"/> objects associated with the <see cref="T:System.Web.UI.DataSourceControl"/>.
        /// </returns>
        protected override System.Collections.ICollection GetViewNames() {
            return new string[] { "MembershipRoles" };
        }

        private sealed class RolesView : DataSourceView {

            /// <summary>
            /// Initializes a new instance of the <see cref="RolesView"/> class.
            /// </summary>
            /// <param name="owner">The owner.</param>
            /// <param name="viewName">Name of the view.</param>
            public RolesView(RolesDataSource owner, string viewName) : base(owner, viewName) { }

            /// <summary>
            /// Gets a list of data from the underlying data storage.
            /// </summary>
            /// <param name="arguments">A <see cref="T:System.Web.UI.DataSourceSelectArguments"/> that is used to request operations on the data beyond basic data retrieval.</param>
            /// <returns>
            /// An <see cref="T:System.Collections.IEnumerable"/> list of data from the underlying data storage.
            /// </returns>
            protected override System.Collections.IEnumerable ExecuteSelect(DataSourceSelectArguments arguments) {
                arguments.RaiseUnsupportedCapabilitiesError(this);

                string[] roles = Roles.GetAllRoles();
                Role[] r = new Role[roles.Length];
                for (int i = 0; i < roles.Length; i++) r[i] = new Role { RoleName = roles[i], UserCount = Roles.GetUsersInRole(roles[i]).Length };
                return r;
            }
        }
    }

    public class RolesDataSourceDesigner : DataSourceDesigner {
        private RolesView roles;

        /// <summary>
        /// Retrieves a <see cref="T:System.Web.UI.Design.DesignerDataSourceView"/> object that is identified by the view name.
        /// </summary>
        /// <param name="viewName">The name of the view.</param>
        /// <returns>This implementation always returns null.</returns>
        public override DesignerDataSourceView GetView(string viewName) {
            if (!string.IsNullOrEmpty(viewName) && !viewName.Equals("MembershipRoles", StringComparison.OrdinalIgnoreCase)) throw new ArgumentOutOfRangeException("viewName", viewName, "Specified view does not exists.");
            if (this.roles == null) this.roles = new RolesView(this, viewName);
            return this.roles;
        }

        /// <summary>
        /// Returns an array of the view names that are available in this data source.
        /// </summary>
        /// <returns>An array of view names.</returns>
        public override string[] GetViewNames() {
            return new string[] { "MembershipRoles" };
        }

        private sealed class RolesView : DesignerDataSourceView {

            /// <summary>
            /// Initializes a new instance of the <see cref="RolesView"/> class.
            /// </summary>
            /// <param name="owner">The owner.</param>
            /// <param name="viewName">Name of the view.</param>
            public RolesView(RolesDataSourceDesigner owner, string viewName) : base(owner, viewName) { }

            /// <summary>
            /// Gets a schema that describes the data source view that is represented by this view object.
            /// </summary>
            /// <value></value>
            /// <returns>An <see cref="T:System.Web.UI.Design.IDataSourceViewSchema"/> object.</returns>
            public override IDataSourceViewSchema Schema {
                get {
                    TypeSchema ts = new TypeSchema(typeof(Role));
                    return ts.GetViews()[0];
                }
            }

            /// <summary>
            /// Generates design-time data that matches the schema of the associated data source control using the specified number of rows, indicating whether it is returning sample data or real data.
            /// </summary>
            /// <param name="minimumRows">The minimum number of rows to return.</param>
            /// <param name="isSampleData">true to indicate that the returned data is sample data; false to indicate that the returned data is live data.</param>
            /// <returns>
            /// A <see cref="T:System.Web.UI.DataSourceView"/> object containing data to display at design time.
            /// </returns>
            public override System.Collections.IEnumerable GetDesignTimeData(int minimumRows, out bool isSampleData) {
                if (minimumRows < 5) minimumRows = 5;
                isSampleData = true;
                Role[] r = new Role[minimumRows];
                for (int i = 1; i <= minimumRows; i++) r[i - 1] = new Role { RoleName = "Role #" + i, UserCount = i };
                return r;
            }
        }
    }
}